package com.yuxl.admin.manager.auth.socket.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuxl.admin.common.socket.domain.SocketInMessage;
import com.yuxl.admin.common.socket.service.WebSocketService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.lang.reflect.Method;

@Slf4j
@Component
public class WebSocketMessageHandler {

    @Resource
    private WebSocketService webSocketService;
    @Resource
    private SocketHandlerRegistry handlerRegistry;
    @Resource
    private ObjectMapper objectMapper;

    public Mono<Void> handle(Flux<WebSocketMessage> inboundMessages, WebSocketSession session, String username, String token) {
        return inboundMessages
                .flatMap(message -> processInboundMessage(session, username, token, message))
                .then();
    }

    private Mono<Void> processInboundMessage(WebSocketSession session, String username, String token, WebSocketMessage message) {
        if (message.getType() == WebSocketMessage.Type.PONG) {
            return Mono.empty();
        }

        String payload = message.getPayloadAsText();
        
        return webSocketService.isUserLoggedIn(username, token)
                .flatMap(isLoggedIn -> {
                    if (isLoggedIn) {
                        return Mono.fromCallable(() -> {
                            log.debug("收到来自用户 {} 的消息: {}", username, payload);
                            return objectMapper.readValue(payload, SocketInMessage.class);
                        }).flatMap(socketMessage -> {
                            socketMessage.setUsername(username);
                            Method handler = handlerRegistry.getHandler(socketMessage.getPath());
                            if (handler != null) {
                                Object bean = handlerRegistry.getBean(socketMessage.getPath());
                                try {
                                    log.debug("调用路径 {} 的处理器，消息内容: {}", socketMessage.getPath(), socketMessage.getPath());

                                    Object result = handler.invoke(bean, socketMessage, session);
                                    if (result instanceof Mono) {
                                        return ((Mono<?>) result).then();
                                    }
                                    return Mono.empty();
                                } catch (Exception e) {
                                    log.error("调用路径 {} 的处理器时出错", socketMessage.getPath(), e);
                                    return sendErrorMessage(session, "内部服务器错误: " + e.getMessage());
                                }
                            } else {
                                log.warn("未找到路径 {} 的处理器", socketMessage.getPath());
                                return sendErrorMessage(session, "无效的消息路径: " + socketMessage.getPath());
                            }
                        }).onErrorResume(e -> {
                            log.error("处理消息时出错", e);
                            return sendErrorMessage(session, "处理您的消息时出错: " + e.getMessage());
                        });
                    } else {
                        log.debug("用户 {} 未登录，正在关闭WebSocket连接", username);
                        return closeSession(session, username);
                    }
                });
    }

    private Mono<Void> sendErrorMessage(WebSocketSession session, String errorMessage) {
        return session.send(Mono.just(session.textMessage(errorMessage)));
    }

    private Mono<Void> closeSession(WebSocketSession session, String username) {
        return Mono.defer(() -> {
            webSocketService.removeSession(username, session);
            if (session.isOpen()) {
                return session.close()
                        .doOnSuccess(v -> log.debug("已关闭用户 {} 的WebSocket连接", username))
                        .doOnError(error -> log.error("关闭用户 {} 的WebSocket连接时出错", username, error));
            } else {
                log.debug("用户 {} 的WebSocket连接已经关闭", username);
                return Mono.empty();
            }
        });
    }
}
